package com.macro.mall.common.thread;

import cn.hutool.core.util.ObjectUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author wwj
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Worker<T> implements Runnable{

    private static final Logger LOGGER = LoggerFactory.getLogger(Worker.class);

    private static final long DEFAULT_TIMEOUT = 500;

    //执行指令
    private Runnable command;


    private Result<T> result = new Result<>();

    private long timeout;

    //拒绝策略
    private Pooled.PoolOverAct poolOverAct = Pooled.PoolOverAct.REJECT;

    // 预备执行时间
    private volatile long prepareExecutionTime;
    //开始执行时间
    private volatile long startExecutionTime;
    //结束执行时间
    private volatile long endExecutionTime;
    // 执行的线程池名称
    private String executorName;


    public Worker(Runnable command) {
        this.command = command;
        this.timeout = DEFAULT_TIMEOUT;
    }

    public Worker(Runnable command, Pooled.PoolOverAct poolOverAct) {
        this.command = command;
        this.timeout = DEFAULT_TIMEOUT;
        this.poolOverAct = poolOverAct;
    }

    public Worker(Runnable command, T result) {
        this.command = command;
        this.result = new Result<>(result);
        this.timeout = DEFAULT_TIMEOUT;
    }

    public Worker(Runnable command, T result, long timeout) {
        this.command = command;
        this.result = new Result<>(result);
        this.timeout = timeout;
    }



    @Override
    public void run() {
        this.startExecution();
        try {
            command.run();
        }finally {
            endExecution();
        }
    }

    public Callable<Result<T>> callable(){
        return Executors.callable(command, result);
    }

    public void setResult(T result) {
        if (ObjectUtil.isNotNull(this.result)) {
            this.result.value = result;
        }
    }

    private void startExecution() {
        this.startExecutionTime = System.currentTimeMillis();
        LOGGER.info("POOL_DISPATCH_TIME, EXECUTOR: {}, TIME: {} ms", this.executorName, this.getPrepareTime());
    }

    /**
     * 结束执行（执行耗时）
     */
    private void endExecution() {
        this.endExecutionTime = System.currentTimeMillis();
        LOGGER.info("POOL_EXECUTE_TIME, EXECUTOR: {}, TIME: {} ms", this.executorName, this.getExecutionTime());
    }
    /**
     * 预备耗时
     *
     * @return
     */
    public long getPrepareTime() {
        return this.startExecutionTime - this.prepareExecutionTime;
    }

    /**
     * 执行耗时
     *
     * @return
     */
    public long getExecutionTime() {
        return this.endExecutionTime - this.startExecutionTime;
    }
}
